# import sys
# sys.path.append('H:\llmapp')
import json
import time

import keyboard
import pyaudio
import torch
from transformers import AutoModelForSpeechSeq2Seq, AutoProcessor, pipeline, AutoModelForCausalLM

from exception.T2Exception import T2Exception
from kimia_infer.api.kimia import KimiAudio
import wave
import sys
from vosk import Model, KaldiRecognizer, SetLogLevel

from llm.DeepSeekLLM import DeepSeekLLM
from stepaudio2.stepaudio2 import StepAudio2
from util.T2util import get_now_str

from funasr import AutoModel
from funasr.utils.postprocess_utils import rich_transcription_postprocess

"""
语音转文字 kimi-audio asr
:param audio_path 语音文件路径
:return 文本
"""
def audio_to_text_kimi_ASR(audio_path:str) -> str:
    # --- 1. Load Model ---
    model_path = "D:\modelscope\kimi-audio-7B-Instruct"
    model = KimiAudio(model_path=model_path, load_detokenizer=True)

    # --- 2. Define Sampling Parameters ---
    sampling_params = {
        "audio_temperature": 0.8,
        "audio_top_k": 10,
        "text_temperature": 0.0,
        "text_top_k": 5,
        "audio_repetition_penalty": 1.0,
        "audio_repetition_window_size": 64,
        "text_repetition_penalty": 1.0,
        "text_repetition_window_size": 16,
    }
    # --- 3. Example 1: Audio-to-Text (ASR) ---
    messages_asr = [
        # You can provide context or instructions as text
        {"role": "user", "message_type": "text", "content": "Please transcribe the following audio:"},
        # Provide the audio file path
        {"role": "user", "message_type": "audio", "content": audio_path}
    ]

    # Generate only text output
    _,text_output = model.generate(messages_asr, **sampling_params, output_type="text")
    print(">>> ASR Output Text: " + text_output)
    return text_output

"""
语音转文字 vosk 
    57m 音频 完成时间为 9s  加了deepseek =>  57s
  
:param audio_path 语音文件路径 仅仅支持wav格式
:deepseek 是否需要deepseek处理。将语音结果进行语义分析为句子，加上标点符号
:return 文本
"""
def audio_to_text_vosk(audio_path:str, deepseek=False, model = None) -> str:
    wf = wave.open(audio_path, "rb")
    if wf.getnchannels() != 1 or wf.getsampwidth() != 2 or wf.getcomptype() != "NONE":
        raise T2Exception("Audio file must be WAV format mono PCM.")
    if model is None:
        model = Model(model_path="D:/modelscope/vosk-model-small-cn-0.22")
    rec = KaldiRecognizer(model, wf.getframerate())
    rec.SetWords(True)
    rec.SetPartialWords(True)
    str_ret = ""
    while True:
        data = wf.readframes(4000)
        if len(data) == 0:
            break
        if rec.AcceptWaveform(data):
            result = rec.Result()
            result = json.loads(result)
            if 'text' in result:
                str_ret += result['text']

    result = json.loads(rec.FinalResult())
    if 'text' in result:
        str_ret += result['text']

    if deepseek:
        str_ret = DeepSeekLLM().get("您是一名语文老师，请将以下这段文字自动加上标点符号组成合理的句子，仅仅回答结果且结果仅仅包含以下出现过的字，如果有错别字可以修改但是不要回答其他的信息：" + str_ret)

    return  str_ret

"""
调用 SenseVoiceSmall模型 对指定音频文件进行语音识别
:param audio_file_path: 音频文件的路径
:return: 识别结果
"""
def audio_to_text_funasr(audio_file_path:str):
    model_dir = "D:/modelscope/SenseVoiceSmall"
    model = AutoModel(
        model=model_dir,
        vad_model="fsmn-vad",
        vad_kwargs={"max_single_segment_time": 30000},
        device="cuda:0",
        disable_update=True,
    )
    res = model.generate(
        input=audio_file_path,
        cache={},
        language="auto",  # "zn", "en", "yue", "ja", "ko", "nospeech"
        use_itn=True,
        batch_size_s=60,
        merge_vad=True,  #
        merge_length_s=15,
    )
    text = rich_transcription_postprocess(res[0]["text"])
    return text

"""
调用 paraformer-zh 模型 对指定音频文件进行语音识别
:param audio_file_path: 音频文件的路径
:return: 识别结果
"""
def audio_to_text_funasr2(audio_file_path:str):
    model = AutoModel(model="D:/modelscope/paraformer-zh-16k", model_revision="v2.0.4",
                      vad_model="fsmn-vad", vad_model_revision="v2.0.4",
                      punc_model="ct-punc-c", punc_model_revision="v2.0.4",
                      # spk_model="cam++", spk_model_revision="v2.0.2",
                      )
    res = model.generate(input=audio_file_path,
                         batch_size_s=300,
                         hotword='魔搭')
    return res


"""
    使用 Step-Audio-2-mini 模型进行离线语音识别

    参数:
        audio_path (str): 音频文件路径（支持常见格式如wav, mp3等）
        model_name (str): 模型名称或本地路径

    返回:
        str: 识别出的文本结果
"""
def audio_to_text_stepaudio2(audio_path, model_name="Step-Audio-2-mini"):

    model = StepAudio2(model_name)
    # token2wav = Token2wav(model_name + '/token2wav')
    messages = [
        {"role": "system", "content": "请记录下你所听到的语音内容。"},
        {"role": "human",
         "content": [{"type": "audio", "audio": audio_path}]},
        {"role": "assistant", "content": None}
    ]
    tokens, text, _ = model(messages)
    return text


"""
测试实时读取麦克风，周期性生产wav文件进行语音识别，模拟实时语音识别
存在漏包情况
还是选择支持实时语音识别的大模型较好
"""
def microphone_speech_recognition():
    # 录音参数配置
    FORMAT = pyaudio.paInt16  # 音频格式
    CHANNELS = 1  # 单声道（语音识别常用）
    RATE = 16000  # 采样率（16kHz适合语音处理）
    CHUNK = 1024  # 每次读取的音频块大小
    RECORD_DURATION = 4  # 每个音频片段的时长（秒）
    OUTPUT_PREFIX = "audio_segment_"  # 输出文件前缀
    # 初始化音频输入
    audio = pyaudio.PyAudio()
    # 打开麦克风流
    stream = audio.open(
        format=FORMAT,
        channels=CHANNELS,
        rate=RATE,
        input=True,
        frames_per_buffer=CHUNK
    )
    model = Model(model_path="D:/modelscope/vosk-model-small-cn-0.22")
    print("开始录音... (按ESC键停止)")
    segment_counter = 0
    try:
        while True:
            # 检查是否按下ESC键
            if keyboard.is_pressed('esc'):
                print("\n检测到ESC键，停止录音")
                break
            # 收集音频数据
            frames = []
            start_time = time.time()
            # 录制指定时长的音频
            while time.time() - start_time < RECORD_DURATION:
                data = stream.read(CHUNK)
                frames.append(data)
            # 生成文件名
            filename = f"{OUTPUT_PREFIX}{segment_counter}.wav"
            # 保存为WAV文件
            with wave.open(filename, 'wb') as wf:
                wf.setnchannels(CHANNELS)
                wf.setsampwidth(audio.get_sample_size(FORMAT))
                wf.setframerate(RATE)
                wf.writeframes(b''.join(frames))
            #
            # print(f"已保存: {filename}")
            segment_counter += 1
            res = audio_to_text_vosk(filename, model=model)
            print(res)

    except Exception as e:
        print(f"录音过程中发生错误: {str(e)}")
    finally:
        # 清理资源
        stream.stop_stream()
        stream.close()
        audio.terminate()
        print("录音已停止，资源已释放")

if __name__ == '__main__':
    print("PyTorch 版本:", torch.__version__)
    print('cuda版本:' + torch.version.cuda)  # 应显示安装的CUDA版本
    # microphone_speech_recognition()
    # audio_to_text_kimi_ASR("H:/llmapp/test_file/fangqi.mp3")
    print(get_now_str())
    # print(audio_to_text_vosk("H:/llmapp/test_file/67ea8cbbe75b4-56s.wav", deepseek=False))
    # print(audio_to_text_funasr("H:/llmapp/test_file/67ea8cbbe75b4-56s.wav")) #执行后没反应？？?
    # print(audio_to_text_stepaudio2("H:/llmapp/test_file/67ea8cbbe75b4-56s.wav", "D:/modelscope/Step-Audio-2-mini"))

    print(get_now_str())


